package client.config;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository;
import org.springframework.security.oauth2.jwt.JwtDecoder;
import org.springframework.security.oauth2.jwt.JwtDecoders;
import org.springframework.security.web.SecurityFilterChain;

/**
 * 模拟访问 R( /user/msg)
 *
 * 0 = {DisableEncodeUrlFilter@8700}
 * 1 = {WebAsyncManagerIntegrationFilter@8699}
 * 2 = {SecurityContextHolderFilter@8698}
 * 3 = {HeaderWriterFilter@8697}
 * 4 = {CorsFilter@8696}
 * 5 = {CsrfFilter@8695}
 * 6 = {LogoutFilter@8694}
 * 7 = {OAuth2AuthorizationRequestRedirectFilter@8693}
 * 8 = {OAuth2AuthorizationRequestRedirectFilter@8690}
 * 9 = {OAuth2LoginAuthenticationFilter@8666}
 *
 * 设置了关注的url -> /login/oauth2/code/*
 * org.springframework.security.config.annotation.web.configurers.oauth2.client.OAuth2LoginConfigurer#init
 * 进行了解析是否匹配
 * org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter#doFilter(jakarta.servlet.http.HttpServletRequest, jakarta.servlet.http.HttpServletResponse, jakarta.servlet.FilterChain)
 *
 *
 * 10 = {DefaultLoginPageGeneratingFilter@10920}
 * 11 = {DefaultLogoutPageGeneratingFilter@10921}
 * 12 = {BearerTokenAuthenticationFilter@10922}
 *
 * 此处进行jwt的辨认
 *
 * 13 = {RequestCacheAwareFilter@10923}
 * 14 = {SecurityContextHolderAwareRequestFilter@10924}
 * 15 = {AnonymousAuthenticationFilter@10925}
 * 16 = {OAuth2AuthorizationCodeGrantFilter@10926}
 * 17 = {SessionManagementFilter@10927}
 * 18 = {ExceptionTranslationFilter@10928}
 * 19 = {AuthorizationFilter@10929}
 *
 * 权限认证失败 由ExceptionTranslationFilter捕获并处理
 *
 * org.springframework.security.web.authentication.DelegatingAuthenticationEntryPoint#commence
 *
 * 并通过 /login/oauth2/code/authcode 进行重定向跳转
 *
 * 完成上面以后，进行访问路径的重定向
 *
 * 如果设置了
 * .sessionManagement((sessionManagement) -> {
 *     sessionManagement.sessionCreationPolicy(SessionCreationPolicy.STATELESS);
 * })
 *
 * 在访问的时候则不会产生缓存数据，最显著的就是不会有曾经目标的访问地址
 * 而第二次 /login/oauth2/code/authcode 访问通过后，会已这样的流程为
 *
 * org.springframework.security.oauth2.client.web.OAuth2LoginAuthenticationFilter 执行完毕调用父类
 * org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter#doFilter(jakarta.servlet.http.HttpServletRequest, jakarta.servlet.http.HttpServletResponse, jakarta.servlet.FilterChain)
 * 成功认证后，访问:
 * org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter#successfulAuthentication
 * 通过
 * org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler#onAuthenticationSuccess
 * org.springframework.security.web.authentication.AbstractAuthenticationTargetUrlRequestHandler#handle
 * org.springframework.security.web.DefaultRedirectStrategy#sendRedirect
 * 通过 返回 / 默认的根路径下面
 * @Override
 * public void sendRedirect(HttpServletRequest request, HttpServletResponse response, String url) throws IOException {
 * 	String redirectUrl = calculateRedirectUrl(request.getContextPath(), url);
 * 	redirectUrl = response.encodeRedirectURL(redirectUrl);
 * 	if (this.logger.isDebugEnabled()) {
 * 		this.logger.debug(LogMessage.format("Redirecting to %s", redirectUrl));
 * 	    }
 * 	if (this.statusCode == HttpStatus.FOUND) {
 * 		response.sendRedirect(redirectUrl);
 *    }
 * 	else {
 * 		response.setHeader(HttpHeaders.LOCATION, redirectUrl);
 * 		response.setStatus(this.statusCode.value());
 * 		response.getWriter().flush();
 *    }
 * }
 */
@Configuration
@EnableWebSecurity
public class SecurityConfig {

    @Value("${spring.security.oauth2.resourceserver.jwt.issuer-uri}")
    String issuerUri;

    @Bean
    public SecurityFilterChain securityFilterChain(ClientRegistrationRepository clientRegistrationRepository, HttpSecurity http) throws Exception {

        /**
         * 在Spring Security中，.oauth2Login(Customizer.withDefaults()) 和 .oauth2Client(Customizer.withDefaults()) 是两个不同的配置，分别用于处理不同的OAuth2流程。让我们分别看一下它们的用途和涉及的URL。
         *
         * 1. .oauth2Login(Customizer.withDefaults())
         * 用途
         * 这个配置用于基于OAuth2的登录（Authorization Code Grant）。通常使用在用户通过第三方身份提供者（如Google, GitHub）登录你的应用。这是涉及用户的互动登录流程。
         * 涉及的URL
         * 一般情况下，这个配置会涉及到以下一些URL：
         * /oauth2/authorization/{registrationId}: 用户点击登录按钮之后，引导用户到第三方身份提供者进行身份认证的URL。
         * /login/oauth2/code/{registrationId}: 第三方身份提供者完成身份验证后，重定向回该URL，并带有授权码。
         * /oauth2/authorize 和 /oauth2/authorize/code/*: 用于处理OAuth2授权和登录结果。
         *
         * 2. .oauth2Client(Customizer.withDefaults())
         * 用途
         * 这个配置用于OAuth2客户端凭证模式（Client Credentials Grant）或者用于后端与OAuth2服务提供者之间的交互，获取访问令牌，用于访问受保护的资源。这不会涉及到具体的用户互动，而是后端应用程序与服务之间的交互。
         * 涉及的URL
         * 这个配置通常涉及到如下一些URL：
         * /oauth2/token: 用于获取访问令牌。
         * /oauth2/jwks: 用于访问JSON Web Key Set，用来验证JWT。
         * 其它相关后端API URL，用于获取、刷新和使用OAuth2 token。
         *
         * 总结
         * .oauth2Login(Customizer.withDefaults()) 是用于处理用户基于OAuth2登录的配置。
         * .oauth2Client(Customizer.withDefaults()) 是用于后端系统作为OAuth2客户端获取访问令牌并访问受保护资源的配置。
         * 希望这能帮助你更清楚地理解这两个配置的区别和它们各自的作用。如果你还有其他问题，随时可以问我。
         */
        http
                .sessionManagement((sessionManagement) -> {
                    sessionManagement.sessionCreationPolicy(SessionCreationPolicy.STATELESS);
                })
                .oauth2Login(Customizer.withDefaults())
                .oauth2Client(Customizer.withDefaults())
                .oauth2ResourceServer(resourceServer -> resourceServer.jwt(Customizer.withDefaults()))// 资源服务
                .authorizeHttpRequests(auth -> auth
//                                .requestMatchers(
//                                        // OAuth2LoginAuthenticationFilter.DEFAULT_FILTER_PROCESSES_URI,
////                                        "/login/oauth2/code/**",
//                                        // OAuth2AuthorizationRequestRedirectFilter.DEFAULT_AUTHORIZATION_REQUEST_BASE_URI
////                                        "/oauth2/authorization/**",
//                                        "/"
//                                )
//                                .permitAll()
                                .anyRequest().authenticated()
//                                .requestMatchers("/home1").authenticated()
//                                .anyRequest().permitAll()
                );
        return http.build();

    }

    /**
     * 从授权服务器发布的meta地址中获取公钥，构建解码器
     * JwtDecoder 用来验证 签名和解码token
     * @return
     */
    @Bean
    public JwtDecoder jwtDecoder() {
        return JwtDecoders.fromIssuerLocation(this.issuerUri);
    }


}